package com.leyou.trade.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.leyou.auth.utils.UserContext;
import com.leyou.common.exception.LyException;
import com.leyou.item.clients.ItemClient;
import com.leyou.item.dto.SkuDTO;
import com.leyou.trade.dto.OrderDTO;
import com.leyou.trade.entity.Order;
import com.leyou.trade.entity.OrderDetail;
import com.leyou.trade.entity.OrderLogistics;
import com.leyou.trade.mapper.OrderMapper;
import com.leyou.trade.service.OrderDetailService;
import com.leyou.trade.service.OrderLogisticsService;
import com.leyou.trade.service.OrderService;
import com.leyou.user.client.UserClient;
import com.leyou.user.dto.AddressDTO;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

import static com.leyou.common.constants.MQConstants.ExchangeConstants.ORDER_EXCHANGE_NAME;
import static com.leyou.common.constants.MQConstants.RoutingKeyConstants.EVICT_ORDER_KEY;

@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {

    @Autowired
    private OrderDetailService detailService;

    @Autowired
    private OrderLogisticsService logisticsService;

    @Autowired
    private ItemClient itemClient;

    @Autowired
    private UserClient userClient;

    @Autowired
    private AmqpTemplate amqpTemplate;

    @Override
    @Transactional
    public Long createOrder(OrderDTO orderDTO) {

        Map<Long, Integer> cartsMap = orderDTO.getCarts();

        this.itemClient.minusStock(cartsMap);

        Order order = new Order();

        order.setStatus(1);
        order.setUserId(UserContext.getUser().getId());

        //全场包邮
        order.setPostFee(0L);
        order.setPaymentType(orderDTO.getPaymentType());


        if (CollectionUtils.isEmpty(cartsMap)) {
            throw new LyException(400, "下单失败，请求参数有误");
        }


        List<SkuDTO> skuDTOS = this.itemClient.listSkuByIds(new ArrayList<>(cartsMap.keySet()));

        if (skuDTOS == null) {
            throw new LyException(400, "下单失败");
        }

        long totalFee = 0;

        for (SkuDTO skuDTO : skuDTOS) {
            Long skuId = skuDTO.getId();

            totalFee += skuDTO.getPrice() * cartsMap.get(skuId);
        }

        order.setTotalFee(totalFee);
        order.setActualFee(totalFee);

        //保存订单，并回显id
        this.save(order);


        List<OrderDetail> orderDetails = skuDTOS.stream().map(skuDTO -> {

            OrderDetail orderDetail = new OrderDetail();
            orderDetail.setOrderId(order.getOrderId());
            orderDetail.setSkuId(skuDTO.getId());
            orderDetail.setNum(cartsMap.get(skuDTO.getId()));
            orderDetail.setTitle(skuDTO.getTitle());
            orderDetail.setSpec(skuDTO.getSpecialSpec());
            orderDetail.setPrice(skuDTO.getPrice());
            orderDetail.setImage(StringUtils.substringBefore(skuDTO.getImages(), ","));

            return orderDetail;
        }).collect(Collectors.toList());


        this.detailService.saveBatch(orderDetails);

        AddressDTO addressDTO = this.userClient.queryAddressById(UserContext.getUser().getId(), orderDTO.getAddressId());

        OrderLogistics orderLogistics = new OrderLogistics();
        orderLogistics.setOrderId(order.getOrderId());

        BeanUtils.copyProperties(addressDTO, orderLogistics);


        this.logisticsService.save(orderLogistics);


        amqpTemplate.convertAndSend(ORDER_EXCHANGE_NAME, EVICT_ORDER_KEY, order.getOrderId());

        return order.getOrderId();

    }

    @Override
    public  void closeOrder() {
        //TODO 要先查询，订单，确定要关闭了，再关闭，并且还原库存

        //先查，已失效订单
        Date deadLine = DateTime.now().minusHours(24).toDate();

        List<Order> evictOrders = this.query().eq("status", 1)
                .lt("create_time", deadLine).list();

        if (CollectionUtils.isEmpty(evictOrders)){
            return;
        }

        //查需要被还原的库存（订单详情）

        //select * from tb_order_detail where order_id in (xxx,xxx,xxx);
        List<OrderDetail> orderDetails = this.detailService.query()
                .in("order_id",
                        evictOrders
                                .stream()
                                .map(Order::getOrderId)
                                .collect(Collectors.toList()))
                .list();

        //要还原的商品id以及num数量对应关系
        Map<Long,Integer> cartsMap = new HashMap<>();

        orderDetails.forEach(orderDetail -> {
            Long skuId = orderDetail.getSkuId();
            Integer num = orderDetail.getNum();

            //存在改数量，不存在，直接添加
            if (cartsMap.containsKey(skuId)){
                cartsMap.put(skuId,cartsMap.get(skuId)+num);
            }else{
                cartsMap.put(skuId,num);
            }
        });

        evictOrders.forEach(evictOrder->{
            evictOrder.setStatus(5);
            evictOrder.setCloseTime(new Date());
        });

        //批量修改
        this.updateBatchById(evictOrders);


        //TODO 考虑数据量，分批次处理，分布式事务
        this.itemClient.plusStock(cartsMap);

        //update tb_order set status = 5,close_time = now() where status = 1 and crate_time < deadLine;
//        update()
//                .set("status",5)
//                .set("close_time",new Date())
//                .eq("status",1)
//                .lt("create_time",deadLine)
//                .update();



    }

    @Override
    public void evictOrderIfNecessary(Long orderId) {
        Order order = this.getById(orderId);

        if (1==order.getStatus()){
            List<OrderDetail> orderDetails = this.detailService.query().eq("order_id", orderId).list();

            //要还原的商品id以及num数量对应关系
            Map<Long,Integer> cartsMap = new HashMap<>();

            orderDetails.forEach(orderDetail -> {
                Long skuId = orderDetail.getSkuId();
                Integer num = orderDetail.getNum();

                //存在改数量，不存在，直接添加
                if (cartsMap.containsKey(skuId)){
                    cartsMap.put(skuId,cartsMap.get(skuId)+num);
                }else{
                    cartsMap.put(skuId,num);
                }
            });
            order.setStatus(5);
            order.setCloseTime(new Date());
            this.updateById(order);

            this.itemClient.plusStock(cartsMap);
        }
    }
}
